#include "main.h"
#include "Debug.h"
#include "error_signals.h"
#include <stdio.h>
#include <stdlib.h>

int main( int argc, char *argv[] )
{	
	// Start of error handling.	
	// This is error handling to display the stack trace of a GPF error.
	// This code has to be done at the beginning of each thread.
	error_signals::AddHandlers();
    pid_t tid = error_signals::GetThreadID();
    error_signals *error_thread = error_signals::GetThread(tid);
    if (error_thread == nullptr)
    {
      error_thread = error_signals::AddThread(tid);
    }
    volatile int val = 0;
    if (error_thread != nullptr)
    {
      error_thread->LineNumberStack = 0;
      val = setjmp(error_thread->position);
    }
    if (val != 0)
    {
	  // This code runs if there's an error.
      error_thread->DisplayErrorMessage(val); // Display a stack trace like C#.
      error_signals::RemoveHandlers();
	  return val;
    }
	// End of error handling.
	DEBUG_FUNCTION
	Function1();
	DEBUG_LINE
	error_thread->ReleaseThread(tid); // Error thread cleanup.	
	return 0;
}

int Function1()
{
	DEBUG_FUNCTION
	printf("This is Function1. It calls function2.\n");
	DEBUG_LINE
	Function2();
}
int Function2()
{
	DEBUG_FUNCTION
	printf("This is function2. It calls function3.\n");
	DEBUG_LINE
	Function3();
}
int Function3()
{
	DEBUG_FUNCTION
	const int BufferSize = 1000;
	char input[BufferSize];
	int value;	
	int inverse;
	const int Divisor = 100;
	DEBUG_LINE
	printf("This is function3.\n");
	printf("This is a simple program to demonstrate catching a program crash and displaying where the error happened.\n");
	printf("When a program crashes, there's nothing that can be done. It's gonna crash.\n");
	printf("But it is possible to catch the error as a signal and display the error location/stack trace.");
	printf("Enter a number and I'll output %d divided by that number.\n",Divisor);
	printf("Press ENTER to quit. Enter 0 to cause a program crash.\n");
	printf("Pressing CTRL Z or CTRL C also cause it to crash.\n");
	printf("You can also kill it from another terminal on the same computer with\nkillall \"ShowErrorsInC++\"\n");
	printf("Negative numbers throw an error that is then caught with try/catch.\n");
	DEBUG_LINE
	while(true) {
		DEBUG_LINE
		try
		{
			DEBUG_LINE
			printf("Enter a number: ");
			DEBUG_LINE
			*input = 0;
			DEBUG_LINE
			fgets(input,BufferSize,stdin);		
			DEBUG_LINE
			if (input[0] <= 13) {
				printf("Have a nice day.\n");
				break;
			}
			DEBUG_LINE
			value = atoi(input);
			DEBUG_LINE
			if (value < 0) {
				throw "Negative numbers are not allowed.";
			}
			DEBUG_LINE
			inverse = Divisor / value;
			DEBUG_LINE
			printf("%d divided by %d = %d.\n",Divisor,value,inverse);
		} catch(const char *error) {
			printf("%s\n",error);
		} catch(...)
		{
			// Notice how a division by zero error isn't caught by this catch in Linux.
			printf("There was an error.");
		}
	}
	DEBUG_LINE
}
